/*
	 
iTransmogrify!

by: Joe Maller 
	joe@joemaller.com
	
Project: http://itransmogrify.googlecode.com/


The following code will be injected into whatever page you're viewing,
automatically detecting and converting many embedded Flash links into 
clickable image links which open in the Safari or the iPhone YouTube player.

Please don't paste this code directly into a page or bookmark. Using the
bookmarklet will automatically pull the most recent stable version of
the code from the Google Code repository.


// javascript:if%28typeof%28iTransmogrify%29%3D%3D%27undefined%27%29%7Bvar%20s%3Ddocument.createElement%28%27script%27%29%3Bs.src%3D%27http%3A%2F%2Fitransmogrify.googlecode.com%2Ffiles%2FiTransmogrify.js%3Fq%3D%27%2B%28new%20Date%29.getTime%28%29%3Bdocument.getElementsByTagName%28%27head%27%29%5B0%5D.appendChild%28s%29%7Dvoid%280%29
if(typeof(iTransmogrify)=='undefined'){
var s=document.createElement('script');
s.src='http://itransmogrify.googlecode.com/files/iTransmogrify.js?q='+(new Date).getTime();
document.getElementsByTagName('head')[0].appendChild(s)
}void(0)

*/



iTransmogrify = {
	jQueryURL: 'http://jqueryjs.googlecode.com/files/jquery-1.2.6.min.js',	// grab JQuery from Google Code
	appleQuickTimeLib: 'http://wdirect.apple.com/main/js/ac_quicktime.js',
	joesInfoURL: 'http://itransmogrify.googlecode.com/',
	imageBaseURL: 'http://itransmogrify.googlecode.com/svn/trunk/images/',	// grab interface images from Google Code SVN

	YTregex: /(?:youtube.com\/v\/|youtube.com\/watch\?v=)([^ .?=&]{11})/, // returns YTids from http://www.youtube.com/v/TOpn32Gg88A and http://www.youtube.com/watch?v=TOpn32Gg88A urls
	YTinternalRegex: /(?:video_id=|watch\?v=)([^ .?=&]{11})/, // regex for extracting YTid from YouTube internal pages like bios, channels, etc
    DMregex: /http:\/\/www.dailymotion.com\/swf\/([\S]+)/, // grab DailyMotion url IDs from swf sources

    // imageBaseURL: 'http://joes-mbp.local:9009/images/',  // use local images
                
	init: function() {
	    parentObject = this; // defined globally for convenience, probably sloppy 
	    if ( this.jQueryVersion = /-([0-9.]+)\.min.js/.exec(this.jQueryURL) )
            this.jQueryVersion = this.jQueryVersion[1];
		if ( typeof jQuery == "undefined" || jQuery.prototype.jquery < this.jQueryVersion ){	// jQuery is not loaded on the page yet or is an older version
			var s = document.createElement('script'),
			    loaded = function() {
			        jQuery.noConflict();
			        parentObject.getObjectAndEmbeds();
		        };
			s.src = this.jQueryURL;
			s.onload = loaded;  // onload handler supported by Safari and Firefox
			s.onreadystatechange = function() { if (this.readyState == 'complete') { loaded() } }; // 'onload' handler for IE
			document.getElementsByTagName('head')[0].appendChild(s);
		} else {
			this.getObjectAndEmbeds()
		}

	},
	
	getObjectAndEmbeds: function(iframe) {
		// transitionting this to a routing function which calls all the other more specific functions
		// TODO: can probably even do away with this by having something scan the host object and call anything object that has a get() method
		var mp3Tags, foundObjects = [];

        if (iframe) var context = iframe.contents();

   //   // collect mp3 items:
   //   mp3Tags = jQuery("param[value*='.mp3']", context).filter( function() { return this.name.toLowerCase() == "flashvars"; });    // players using FlashVars
   //   mp3Tags = mp3Tags.add(jQuery("embed[flashvars*='.mp3']", context));
   //   mp3Tags = mp3Tags.add(jQuery("param[value*='.mp3']", context).filter( function() { return this.value.indexOf('mp3_file') > -1; }));  // for kink.fm
   //   
   //   mp3Tags.each(function() {
   //   	var mp3url;
   //       if (mp3url = parentObject.getMP3url(this)) {
   //   	    foundObjects.push( {
   //   						_type: 'mp3', 
   //                           _obj: function(item) { 
   //                                   // figure out which DOM object to replace
   //                                   if (iframe && iframe.attr('id').indexOf('iTransmogrify_') == 0)   // this is a created iFrame
   //                                       return iframe;
   //                                       
   //                                   if( jQuery(item).parent().is('object') ) 
   //                                       return jQuery(item).parent();
   //                                       
   //                                   return jQuery(item);
   //                               }(this),
   //   						_mp3: mp3url
   //   						});
   //       }
   //   });

// working on these:
        this.getVodPodEmbeds(context);
        this.youtube.get(context);
        this.mp3.get(context);
        
// end
        this.flickr.get(context);
        this.blipTv.get(context);
        this.getViperVideoQuicktags(context);
        this.getRevverLinks(context);
        this.getTedLinks(context);           // convert TED embedded and detail page videos to MP4 alternates
        this.getSideLoadLinks(context);      // convert SideLoad playback links
        this.getDailyMotionLinks(context);      // convert DailyMotion links          
        this.getKinkFmLinks(context);      // convert kink.fm links in place
        this.sevenload.get(context);
        this.breakdotcom.get(context);
        this.getCrunchyRollLinks(context);
        
        jQuery(foundObjects).each( function() { parentObject.replaceLinks(this); } );   // do YouTube and MP3 foundObjects

        
        // grab any remaining object/embed tags and convert them
        this.unsupported.get(context);
        
        // load the bookmarklet for every frame on the page:
        if(!iframe)
            this.loadInFrames();

        this.doStats()
	},
	
	
	loadInFrames: function() {
	    
	    jQuery('iframe').each(function(){
	        var thisFrameSrc = jQuery(this).attr('src');
            console.log(thisFrameSrc);
            if ( jQuery(this).attr('src').split('/')[2] == document.location.host )    // only try if host matches domain of source
                parentObject.getObjectAndEmbeds( jQuery(this) )   // try prevents errors trying to read contents of frames pointing to different domains
        })
	},


    youtube: {
        pageBase: 'http://www.youtube.com/watch?v=',
        redirectBase: 'http://joemaller.com/services/redirector.php?YTid=',  // redirect to escape iPhone-YouTube jail
        
        get: function(context) {
                var thisParent = this,
                    selectors = [ 
                                  'object[src*=youtube.com]', 
                                  'object[data*=youtube.com]',
                                  'param[value*=youtube.com]',
                                  'embed[src*=yout2ube.com]'
                                ];
                            
                            if ( window.location.host.match( /youtube.com$/ ) )
                                selectors.push(['#watch-player-div embed',      // standard YouTube pages
                                                '.profileEmbedVideo object',    // Grab embeds from YouTube  bio pages
                                                '.profileEmbedVideo embed',
                                                '#watch-noplayer-div'   // YouTube pages with no embedded player
                                               ]) 
            
                jQuery(selectors.join(',')).each( function() {
                    
                        var id, title, duration,
                            obj = jQuery(this);
                            obj = ( obj.parent().is('object') ) ? obj.parent() : obj;
                            
                            if (id = parentObject.YTregex.exec(obj.html())) id = id[1];
                            if ( typeof(swfArgs) != "undefined" ) {     // for standard view pages, use the existing javascript vars
                                id = swfArgs.video_id;
                                duration = swfArgs.l;
                            }
                            if ( typeof(pageVideoId) != "undefined" ) id = pageVideoId; // for profile pages
                            if ( typeof(fullscreenUrl) != "undefined" && ( title = /&title=(.*)/.exec( fullscreenUrl ) ) )  title = title[1];

                            thisParent.replace( {
                                                  _type: 'youtube',
                                                  _obj: obj,
                                                  _id: id, 
                                                  _page: ( ( window.location.host.match( /youtube.com$/ ) ) ? thisParent.redirectBase : thisParent.pageBase ) + id,
                                                  _img: 'http://img.youtube.com/vi/' + id + '/0.jpg',
                                                  _duration: duration,
                                                  _title: title,
                                                  _w:  (jQuery(this).is('#watch-noplayer-div')) ? 480 : null,
                                                  _h:  (jQuery(this).is('#watch-noplayer-div')) ? 385 : null
                                              });
                });	
        },
        
        urlHandler: function( url ) {
            /// this will be where something like the vodpod extractor can send the known YouTube url. It would simply extract the ID, call JSON and pass the result to replace
        },
        
        replace: function( iT ) {
            parentObject.replaceLinks( iT );
        },
        
    },


    mp3: {
       thisParent: null,    
       
       get: function(context) {
            thisParent = this;
            var     regex = /=((?:http|\/)[^&]*\.mp3)/,	// extracts full-path URLs ending in .mp3 from query strings used frequently in param flashvars
        	
                selectors = [  // 'embed[src*=audio_file]',      // tumblr's player
                                'param[flashvars*=.mp3]',        // generic param flashvars player with visible mp3 tag
                                'embed[flashvars*=.mp3]'        // generic embed flashvars player with visible mp3 tag
                            ];

            if ( typeof(replaceIfFlash9) == 'function') 
                thisParent.replaceTumblr(context);


            if ( window.location.host.match( /pownce.com$/ ) && typeof(audioplayer) == 'function') 
                thisParent.replacePownce(context);
 
             jQuery( selectors.join(',') ).each( function() {
                var mp3url = regex.exec(jQuery(this).html());
                
                console.log( jQuery(this).html() )
                console.log(mp3url)                

                // thisParent.replace( {
                //                       _type: 'mp3',
                //                       _obj: jQuery(this),
                //                       _mp3: mp3url,
                //                   });
            })
        },
        
        replacePownce: function(context) {
            jQuery('.audioplayer div[id^=audio] embed, .audioplayer div[id^=audio] script').each(function(){
                var mp3url, 
                    obj = jQuery(this);
                    
                if ( obj.is('embed') )                   
                    mp3url = unescape( obj.attr('flashvars').substring(4) );
                    
                if ( obj.is('script') )                   
                    mp3url =  /audioplayer\('([^']+)/.exec( obj.html() )[1];
                                 
                console.log(mp3url)

// something Pownce is doing is sending the file as a download. Force it into QT player by sending it as mp4
                
                // empty object first, insert div?
                
                thisParent.replace( {
                                      _type: 'mp4',
                                      _obj: jQuery(this),
                                      _mp4: mp3url,
                                      _img: mp3url,
                                      _w: 250,
                                      _h: 224
                                  });
                
                })
        },
        
        
        replaceTumblr: function(context) {
            jQuery('span[id^=audio_player]').each(function(){
                
                var w = /width="([0-9]+)"/.exec( jQuery(this).next('script').text() )[1],
                    h = /height="([0-9]+)"/.exec( jQuery(this).next('script').text() )[1],
                    mp3url = /audio_file=(http[^&]+)/.exec( jQuery(this).next('script').text() )[1];
                
                mp3url = mp3url.replace(/http:\/\/[^\/]+/, 'http://www.tumblr.com');  // save a redirect
                mp3url += '?plead=please-dont-download-this-or-our-lawyers-wont-let-us-host-audio';
                
                thisParent.replace( {
                                      _type: 'mp3',
                                      _obj: jQuery(this),
                                      _mp3: mp3url,
                                      _w: w,
                                      _h: h
                                  });
            })
            
        },
        
        
        replace: function( iT ) {
            parentObject.replaceLinks( iT );
        }
    },
    
    
	getTedLinks: function(context) {
        var TEDitems,
            TedLookupUrl = 'http://joemaller.com/services/ted_lookup.php?ted=',
            TEDregex = /file=(http:\/\/static.videoegg.com\/ted\/movies\/[^.]+\.flv)&/;

    	if ( window.location.host.match( /ted.com$/ ) )  {    	    
            TEDitems = jQuery('#videoPlayerSwf')
        } else {
            TEDitems = jQuery('param[value*=static.videoegg.com/ted/movies]');
        }

        TEDitems.each( function() {
            var flv, obj;
           
            if ( flv = TEDregex.exec(this.value) ) {
                 flv = flv[1].split('/').pop();
                 obj = jQuery(this).parent();
            } else if ( flv = /http:\/\/(?:\w*\.)?ted.com\/.*\/([0-9]+)$/.exec(window.location.toString()) ) {
                 flv = flv[1];
                 obj = jQuery(this);
            }

            // Note we're using the newer notation here, everything will transition to match this
            jQuery.getJSON( TedLookupUrl + flv + '&callback=?', function(json){
               json._obj = obj;
               json._type = "ted";
               json._bg = "#000";
               json._w = obj.attr('width');
               json._h = obj.attr('height');
               json._duration =  json._duration.substring(3);
               
               if (json._title == '')
                    json._title = "Compatible alternate content not found."
               
               parentObject.replaceLinks( json );
               
            });
        })
	},
	
		
	//TODO: redo DailyMotion as an object. It's already half-broken, just start over.
	getDailyMotionLinks: function(context) {
        var interFrame,
            dailyMotionItems = jQuery("embed[src*='dailymotion.com/swf']", context); // get standard YouTube embeds and UFO inserted Webkit bare-embeds
        // dailyMotionItems = dailyMotionItems.add(jQuery("object[data*='dailymotion.com']", context)); // get Mozilla UFO bare objects
       // console.log("dailymotion items")
       // console.log(dailyMotionItems)
        dailyMotionItems.each(function() {
                      parentObject.replaceLinks( {
                          type: "dailymotion",
                          jq: jQuery(this).parent(),
                          DMid: parentObject.getDMid(this)
                      });
//         parentObject.getDMtitles(parentObject.getDMid(this));
        });
	},
	
	getViperVideoQuicktags: function(context) {
	   	// Viper Video Quicktags:  
        //     http://www.viper007bond.com/wordpress-plugins/vipers-video-quicktags/
        //     http://wordpress.org/extend/plugins/vipers-video-quicktags/
        var YTid, 
            items = jQuery('.vvqyoutube', context);

        items.each( function() {
            if(!jQuery(this).children().eq(0).is('object')) {
                if ( YTid = parentObject.YTregex.exec( jQuery(this).html() ) ) {
                          parentObject.replaceLinks( {
                              type: "youtube",
                              jq: jQuery(this),
                              YTid: YTid[1],
                              _type: 'youtube',
                              _obj: jQuery(this),
                              _id: YTid[1],
                              _img: 'http://img.youtube.com/vi/' + YTid[1] + '/0.jpg',
                              _page: 'http://www.youtube.com/watch?v=' + YTid[1],
                              _w: jQuery(this).width(),
                              _h: jQuery(this).height()
                          } );
                      
                          // parentObject.getYTTitles(YTid[1]);
                    }
                }
            }
        )
    },
	
	
	getVodPodEmbeds: function(context) {
       jQuery('embed[src^="http://widgets.vodpod.com"]', context).each( function(){
           var thisItem = this
           if ( vodPodId = /vodpod.com\/.*ExternalVideo\.([0-9]+)/.exec( jQuery(this).attr('src') ) ) {
               jQuery.getJSON( 'http://joemaller.com/services/vodpod_id_extractor.php?vodpod=' + vodPodId[1] +'&callback=?', function(json) {
                    json._obj = thisItem;
                    json._w = jQuery(thisItem).width(); 
                   // console.log(json)
                }
            )}
        })
	},
	
	flickr : {
	    get: function(context) {
            var thisParent = this, 
                flickrAPIurl = ['http://api.flickr.com/services/rest/?method=flickr.photos.getInfo&format=json&api_key=5479719afe2139329effb862462a0030&photo_id=', '&jsoncallback=?'],
                selectors = ['embed[src*=flickr.com/apps/video]'];
    
            if ( window.location.host.match( /flickr.com$/ ) && typeof(page_p.video_thumb_src) != 'undefined' )
                this.videoReplace(context); // this is a flickr page

            jQuery(selectors.join(',')).each( function() {
                var obj = jQuery(this);
                    photoID = /photo_id=([0-9]+)/.exec( jQuery(this).attr('flashvars') )

                if ( photoID[1] ) {
                    jQuery.getJSON( flickrAPIurl.join( photoID[1] ), function(json) {

                        if ( json.stat = 'ok' )
                            json = json.photo;      // save keystrokes by jumping down a level
                            
                        json._type = 'flickrvideo';
                        json._typeLabel = 'Flickr';
                        json._page = json.urls.url[0]._content;
                        json._title = json.title._content;
                        json._img = 'http://farm' + json.farm + '.static.flickr.com/'+ json.server + '/' + json.id + '_' + json.secret + '.jpg';
                        json._obj = obj;
                        
                        parentObject.unsupported.replace( json )
                    })
                }
            });
            
            jQuery('iframe[src^=http://www.flickr.com/apps/badge/badge_iframe.gne]', context).each(function(){thisParent.badgeReplace(this)})
                
        },
	        
        videoReplace: function(context) {
            parentObject.unsupported.replace( { _type : 'flickrvideo',
                                               _typeLabel : 'Flickr',
                                               _obj : jQuery('#photoswftd .photo_gne_video_wrapper_div', context).parent(),
                                               _page : '',
                                               _img : page_p.video_thumb_src,
                                               _title : page_p.title + ''
                                         } );
        },
	        
        badgeReplace: function(b){
            var item, flickrID,
                obj = jQuery(b);

            if ( flickrID = /person_id=([0-9]+@[A-Z][0-9]{2})/.exec( unescape( obj.attr('src') ) ) ) {
                flickrID = flickrID[1];
                jQuery.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?id=" + flickrID + "&format=json&jsoncallback=?", function(data){
                    item = jQuery(document.createElement('div')).attr('id', parentObject.nameCleaner(flickrID)).css({margin: '0 0 1px 1px', width:'113px', height: '151px', lineHeight: '1px', backgroundColor: '#fff' }).replaceAll(obj);
                    item.parent().after(jQuery(document.createElement('div')).html('MobileSafari enabled by <a href="http://iTransmogrify.googlecode.com" target="_new">iTransmogrify!</a>').css({textAlign: 'center', fontSize: '10px', lineHeight: '14px'}))
                    jQuery.each( data.items, function(i, item) {
                        jQuery(document.createElement('a')).attr( { href: item.link, title: item.title, target: '_new' } )
                                .append( jQuery(document.createElement('img')).attr( { src: item.media.m.replace('_m.jpg', '_s.jpg'), alt: item.title } )
                                .css( { width: "37px", height: "37px", margin: ( ( i % 3 == 2 ) ? '0 0 1px 0' : '0 1px 1px 0') } ) )    // margins are conditional to prevent background spill
                                .appendTo('#' + parentObject.nameCleaner(flickrID));
                        if ( i == 11 ) return false; // mimic badge and insert 12 most recent images
                    });
                });
            }
        }
	},
		
	
	getRevverLinks: function(context) {
	    var revverAffiliate = '', 
    	    //  revverAffiliate = ', {"affiliate": 169801}',  // Add affiliate links pending response from Revver
	        revverAPI = ['https://api.revver.com/json/1.0?method=open.video.find&params=[{"ids":[',']},["id","title","duration", "quicktimeMediaUrl", ["thumbnailUrl",{}], "status"]' + revverAffiliate + ']&callback=?'],
            revverItems = jQuery( 'script[src*=flash.revver.com], embed[src*=flash.revver.com/player]', context)

        revverItems.each( function() {
            var mediaId, affiliateId, w, h, obj;                
            if ( jQuery(this).is('script') ) {
                if ( mediaId = /mediaId:([0-9]+)/.exec( jQuery(this).attr('src') ) ) mediaId = mediaId[1];
                if ( affiliateId = /affiliateId:([0-9]+)/.exec( jQuery(this).attr('src') ) ) affiliateId = affiliateId[1];
                if ( w = /width:([0-9]+)/.exec(jQuery(this).attr('src')) ) w = w[1];
                if ( h = /height:([0-9]+)/.exec(jQuery(this).attr('src')) ) h = h[1];

                obj = jQuery(this);
                if ( obj = jQuery('div[id^=revver' + mediaId + ']') )
                    jQuery(this).remove(); // remove the scripts and use the div instead
            }
                            
            if ( jQuery(this).is('embed') ) {
                if ( mediaId = /mediaId=([0-9]+)/.exec( jQuery(this).attr('src') ) ) mediaId = mediaId[1];
                if ( affiliateId = /affiliateId=([0-9]+)/.exec( jQuery(this).attr('src') ) ) affiliateId = affiliateId[1];
                if ( w = jQuery(this).attr('width') ) {};
                if ( h = jQuery(this).attr('height') ) {};

                obj = jQuery(this);
                if ( jQuery(this).parent().is('object') ) 
                    obj = jQuery(this).parent()
            }
                    
            if ( mediaId ) { 
                jQuery.getJSON( revverAPI.join(mediaId), function(json){

                    // revver returns a single item array, so cast that right away to save keystrokes
                    json = json[0];
                    if ( json.status == 'online' ) {
                        json._img = json.thumbnailUrl;
                        json._obj = obj;
                        json._id = mediaId;
                        json._page = 'http://www.revver.com/video/' + json._id;
                        json._type = 'revver';
                        json._mp4 = json.quicktimeMediaUrl;
                        json._title = json.title;
                        json._bg = "#000";
                    } 
                    json._w = w;
                    json._h = h;
                    if ( json.status != 'online' ) json._title = "Revver Video status: " + json.status;

                    parentObject.replaceLinks( json );
                });
            }           
        })
	},
	
	
	getDMtitles: function(DMid) {
	   var DMTitleURL = 'http://pipes.yahoo.com/joemaller/dmtitles?_render=json&DMid=' + DMid + '&_callback=?';
	   
	    jQuery.getJSON( DMTitleURL + '', function(json){
            var title = [];
            jQuery.each( json.value.items, function(item, i){ title.push (i.content) })
            parentObject.swapTitle(jQuery('#' + parentObject.nameCleaner(DMid) + ' .YTtitle'), title.join(' - '));
            // console.log(json)
            // console.log(title)
            
            // TODO: Is this even working?
        });
	},	
	

    blipTv: {
        'get': function(context) {
            var thisParent = this, 
                selectors = [ 'param[value*=blip.tv]',              // legacy player embed code
                              'embed[src*=blip.tv/play]',           // new-style player embed
                              'embed[src*=blip.tv/scripts/flash]',  // new-style player embed
                              'div[id^=blip_movie_content_]'        // legacy player
                            ];
                            //TODO: not replacing embeds on Mahalo Daily, no ID?:   http://daily.mahalo.com/2007/12/06/md019-the-room-interview-with-tommy-wiseau/

            jQuery(selectors.join(',')).each( function() {
                JSONurl = thisParent.getId(this);
                var obj = ( jQuery(this).parent().is('object') ) ? jQuery(this).parent() : jQuery(this);
                if (JSONurl) {
                    thisParent.JSONreplace(obj, JSONurl);
                }
            })
        },
        
        getId: function(item) {
            var id,
                blip_jsonUrl = ['http://blip.tv/', '?skin=json&file_type=m4v&callback=?'],
                blip_id_translator = "http://joemaller.com/services/blip_id_extractor.php?blip=";
                
            if ( id = /_([0-9]+)$/.exec(item.id) ){
                return blip_jsonUrl.join( 'posts/' + id[1]);}

            if ( id = /blip.tv\/rss\/flash\/([0-9]+)&/.exec( item.value ) )
                return blip_jsonUrl.join( 'posts/' + id[1] );

            if ( id = /blip.tv\/rss\/flash\/([0-9]+)&/.exec( unescape(item.src)  ) )
                return blip_jsonUrl.join( 'posts/' + id[1] );

            if ( id = /blip.tv\/(file|posts)\/([0-9]+)/.exec( (item.value) ) )
                return blip_jsonUrl.join( id[1] + '/' + id[2] );

            if ( id = /blip.tv\/play\/(.*)/.exec( (item.src) ) )    // new style IDs
                return blip_id_translator + id[1]+ '&callback=?';
        },
        
        JSONreplace: function(obj, JSONurl) {
            jQuery.getJSON( JSONurl, function(json){
               
                if (json.value){
                    // Yahoo! pipes bookmark handler, recast the variable with a subelement to save keystrokes
                    json = json.value.items[0];
                } else {
                    // standard Blip json response, result is a single array, cast that right away to save keystrokes
                    json = json[0].Post;
                }

                // remap some of the renamed items from Yahoo Pipes
                // also check media:group for .m4v and .mp4 media files.
                if ( json['media:group']){
                    var i;
                    for (i in json['media:group']['media:content']) {
                        if ( json['media:group']['media:content'][i].url.match(/\.m4v|mp4/) ){
                            json.media = json['media:group']['media:content'][i]
                            json.media.duration = json['blip:runtime']
                            break;
                        }
                    }
                    json.thumbnailUrl = json['media:thumbnail'].url;
                };

                json._type = 'blip.tv';
                json._typeLabel = 'blip.tv';
                json._obj = obj;
                json._img = json.thumbnailUrl;
                json._id = json.itemId;
                json._page = json.url;
                json._title = json.title;
                json._w = (json._obj.attr('width')) ? json._obj.attr('width') : json._obj.width();
                json._h = (json._obj.attr('height')) ? json._obj.attr('height') : json._obj.height();
                json._bg = "#000";

                if ( json.media.url.match(/\.m4v|mp4/) ){                    
                    // console.log('in match: '+ json._title)
                    json._mp4 = json.media.url;
                    json._duration = json.media.duration;

                    parentObject.replaceLinks( json );
                } else {
                    // console.log('in match: '+ json._title)
                    parentObject.unsupported.replace( json );
                }
            });
        }
    },
    
    
    breakdotcom: {
        'get': function(context) {
            var thisParent = this, 
                selectors = [ 'param[value*=embed.break.com]',            
                              'embed[src*=embed.break.com]',
                              '#playerwrap #defaultDiv object',
                              '#playerwrap #defaultDiv embed'          
                            ];

            jQuery(selectors.join(',')).each( function() {

                var obj = ( jQuery(this).parent().is('object') ) ? jQuery(this).parent() : jQuery(this);
                if ( JSONurl = thisParent.getId(this) )
                    thisParent.JSONreplace(obj, JSONurl);
            })
        },
        
        getId: function(item) {
            var id,
                breakRegex = /embed.break.com\/([^&"]*)/,
                jsonUrl = ['http://joemaller.com/services/break_extractor.php?break=', '&callback=?'];
                
            if ( (id = breakRegex.exec(item.value)) || (id = breakRegex.exec(item.src)))
                return jsonUrl.join( id[1] )

            if( id = breakRegex.exec(jQuery('textarea').text()) )
                return jsonUrl.join( id[1] )
        },
        
        JSONreplace: function(obj, JSONurl) {
            jQuery.getJSON( JSONurl, function(json){
                json._obj = obj;
                if ( window.location.host.match( /break.com$/ ) ) {
                    json._title = document.title.substring( 0, document.title.length - 6 );
                    json._page = '';    // link would be circular, but not excepted because of the redirect, remove the link.
                }
                parentObject.unsupported.replace( json );
            })
        }
    },
    
    
    sevenload: {
        'get': function(context) {
            var thisParent = this, 
                selectors = [ 'script[src*=sevenload.com]',            
                              'object[id^=sevenloadPlayer_]'          
                            ];

            jQuery(selectors.join(','), context).each( function() {
                if ( jQuery(this).is('script') ){
                    var parts = /\/\/([^.]*\.)sevenload.com\/pl\/([^\/]+)\/([0-9]+)x([0-9]+)/.exec(this.src)
                    
                    obj = jQuery(this);
                    if ( obj = jQuery('object[id^=sevenloadPlayer_' + parts[2] + ']') )
                        jQuery(this).remove(); // remove the scripts and use the div instead
                        
                    parentObject.unsupported.replace( { _type : 'sevenload',
                                                       _typeLabel : 'sevenload',
                                                       _obj : obj,
                                                       _w : Number( parts[3] ),
                                                       _h : Number( parts[4] ),
                                                       _page : 'http://' + parts[1] + 'sevenload.com/videos/' + parts[2],
                                                       _title : 'Video Page'
                                                      } );
                }
            })
        },
        
        getId: function(item) {
            var id,
                breakRegex = /embed.break.com\/([^&"]*)/,
                jsonUrl = ['http://joemaller.com/services/break_extractor.php?break=', '&callback=?'];
                
            if ( (id = breakRegex.exec(item.value)) || (id = breakRegex.exec(item.src)))
                return jsonUrl.join( id[1] )

            if( id = breakRegex.exec(jQuery('textarea').text()) )
                return jsonUrl.join( id[1] )
        },
        
        JSONreplace: function(obj, JSONurl) {
            jQuery.getJSON( JSONurl, function(json){
                json._obj = obj;
                if ( window.location.host.match( /break.com$/ ) ) {
                    json._title = document.title.substring( 0, document.title.length - 6 );
                    json._page = '';    // link would be circular, but not excepted because of the redirect, remove the link.
                }
                parentObject.unsupported.replace( json );
            })
        }
    },
    
    getCrunchyRollLinks: function(context) {
        // this all works, the problem is with the h.264 encodes on crunchyroll.com, they're not iPhone compatible
        // leaving it in, just in case they fix stuff
    	if ( window.location.host.match( /crunchyroll.com$/ ) ) {
            var crunchyMp4 = /file=((?:[^&]+video.mp4)|(?:.*format=h264))/.exec(unescape(window.FO.flashvars));
            if ( crunchyMp4[1] ) {
               this.replaceLinks( {
                    _type: 'mp4',
                    _obj: jQuery('#embed_vid').empty(),
                    _img: crunchyMp4[1],
                    _page: document.location.href,
                    _title: document.title.substring(14),
                    _mp4: crunchyMp4[1],
                    _duration: '--:--',
                	_w: jQuery('#embed_vid').width(),
                	_h: jQuery('#embed_vid').height(),
                	_bg: '#000'
                } )
            }
        }
    },
    

    getSideLoadLinks: function(context) {
        // rather than doing all sorts of ninja selector hackery, we're just going to replace their function. Hizzah!
        if (typeof(flashProxy) == 'undefined')  return false    // bail out if there are no sideload links
        flashProxy.call = function(blah, mp3url, mp3Title) {return false;}
        
        // the stack idea is from http://fmarcia.info/jquery/stack/
        // referenced here: http://groups.google.com/group/jquery-en/browse_thread/thread/456709277ec26679/68dcabe65083212c?lnk=gst&q=each+delay#68dcabe65083212c
        
        var stack = {
			'delay': 50,
			'actions': [],
			'run': function() {
				if ( stack.actions.length ) {
				     stack.actions.shift()();
				     setTimeout(stack.run, stack.delay);
				}
			}
		};
		
        
        jQuery('a[href*=flashProxy]').each(function(){
            
            var mp3Parts = (/'\s*,\s*'(.*)'\s*,\s*'(.*)'\)/).exec(this.href),
                newRow = jQuery(this).parent().parent().after('<tr height="36"><td colspan="99" ><p/></td></tr>').next().find('p'),
                button = {
                    type: "mp3",
                    jq: newRow,
                    url: mp3Parts[1],
                    title: unescape(mp3Parts[2])
                };
            
            stack.actions.push(function(){
                parentObject.replaceLinks( button );
            })
        })
        stack.run();
    },
    
	
	getKinkFmLinks: function(context) {
   		var buttons = jQuery('a img[src*="play_button.gif"]', context).parent(),
   		    kinkRegex = /, ?(\d+)\)/;   // extract kink id from javascript links

        buttons.each( function() {

            if ( kinkPageID = kinkRegex.exec( jQuery(this).attr('href') ) )
                 kinkPageID = kinkPageID[1];

            parentObject.replaceLinks( {
                type: "mp3",
                jq: jQuery(this),
                url:kinkPageID
            } );

            jQuery( '#' + parentObject.nameCleaner(kinkPageID) ).find('.YTtitle').html('Click to fetch mp3 address');
            jQuery( '#' + parentObject.nameCleaner(kinkPageID) ).click( function() {
    
                var kinkSource, kinkTitle;
                currentItem = this.id;

                parentObject.swapTitle(jQuery('#' + currentItem).find('.YTtitle'), 'fetching address...');   // Change title to "fetching..."

                var interFrame = jQuery('<iframe src="http://www.kink.fm/topic/play_window.php?audioId=' + (this.id.substring(3))
                                        + '" width="25" height="25" style="position: absolute; width:25px; height: 25px; left: 1000px" name="iTransmogrify_' 
                                        + currentItem + '" id="iTransmogrify_' + currentItem + '" />'
                                       )
                interFrame.load( function() {
                    if ( kinkSource = parentObject.mp3regex.exec( jQuery('#iTransmogrify_' + currentItem).contents().find('embed').attr('src') ) )
                         kinkSource = kinkSource[1];
            
                    if ( kinkTitle = (/ - (.*)$/).exec( jQuery('#iTransmogrify_' + currentItem).contents().find('title').text() ) )
                         kinkTitle = kinkTitle[1];
 
                     jQuery('#iTransmogrify_' + currentItem).remove();
                     parentObject.swapTitle(jQuery('#' + currentItem).find('.YTtitle'), kinkTitle);   // swap out the title
                     jQuery('#' + currentItem).find('.YTlink').attr('href', kinkSource);    // point href of main link to the mp3
                     jQuery('#' + currentItem).unbind('click')      // remove previous click handler
                })

                jQuery(this).before(interFrame)

                return false;
            })
        })
	},

		
	getYTTitles: function(YTid) {
		var gdataURL = "http://gdata.youtube.com/feeds/videos/" + YTid + "?alt=json-in-script";
		// can't use JQuery to insert these scripts because of a bug in Google's GData handling 
		// of single-item YouTube feeds, if there's a callback specified then Google spits back 
		// a bad result more info here: http://code.google.com/p/gdata-issues/issues/detail?id=295
		
        // gdata is a placeholder to workaround a Google feed bug with jQuery JSON requests: 
        //      http://code.google.com/p/gdata-issues/issues/detail?id=295
        //      http://code.google.com/p/gdata-issues/issues/detail?id=390
		gdata = { io: { handleScriptLoaded: function(data){ parentObject.YTJSONhandler(data) } } }  
		
        var s = document.createElement('script');
        s.src = gdataURL;
        s.id='script' + YTid;    // for cleanup later on, also used to prevent double-inserted titles
        document.getElementsByTagName('head')[0].appendChild(s); // Gdata will callback to insertYTTitles() after loading the script
		
		// build a fake error handler
		// this will call the insertYTTitles after 2 seconds. The timer clears 
		// in the JSON handler so it will only call on bad script loads
		this['timer' + YTid ] =  setTimeout(function(){ parentObject.insertYTTitles(YTid) }, 4000);	// this is our fake error handler
	},
	
	
	YTJSONhandler: function(data) {
	    // Google recently changed the format of the JSON object's link container. 
	    // this should now recognizes the old version and the new one.
	    // checks for length, which should be a two-item array
	    
	    switch (2) {  
        case ( ( YTid = this.YTregex.exec( data.entry.link[0].href ) ).length ):
            YTid = YTid[1]
            break;

        case ( ( YTid = this.YTregex.exec( data.entry.link[1].href ) ).length ):
            YTid = YTid[1]
            break;

        default:
            YTid = false;
	    }
	    
		if ( YTid ) {
			 this[ YTid ] = data.entry;	// store YT JSON info under the unique ID of the movie
			 clearTimeout( this[ 'timer' + YTid ] )	// clear the timeout (the fake an error handler)
		     this.insertYTTitles( YTid );
		}
	},
	
	insertYTTitles: function(YTid) {
		if ( !this[YTid] ) {
			// movie info failed to load, no JSON data loaded
			var YTtitle = 'Video not found', 
			    YTtime = '--:--';
		} else {
			if ( this[YTid] && jQuery('#script' + YTid).length ) {
				// JSON data loaded and script still exists
				var YTtitle = this[YTid].title.$t,
                    YTtime = this.formatSeconds( this[YTid].media$group.yt$duration.seconds );
			}
		}
        // TODO: unify this with the same formatting in replaceLinks
        YTtitle = YTtitle + ' &nbsp; <span style="color:#888; font-family:Helvetica;">' + YTtime + '</span>';   // get this out of here
		jQuery('#script' + YTid).remove(); // remove this specific JSON script

        this.swapTitle( jQuery('#' + this.nameCleaner(YTid) + ' .YTtitle'), YTtitle )
	},
	
	swapTitle: function(jq, title) {
	    if ( title.length < 1 ) return false;
	    setTimeout( function() {
	        jq.animate( { textIndent: "-" + jQuery(this).width() +"px" }, 300, function() { jQuery(this).html(title) } ).animate({textIndent: 0}, 500)
		}, 250);
	},
    
	nameCleaner: function(oldName) {
	    // scrubs a string to make it usable as an id/class name
	    return 'iT_' + unescape(oldName).replace(/\W/g, "_");
	},
	
	
	getMP3titles: function(mp3url) {
        this.swapTitle(
            jQuery('#' + this.nameCleaner(mp3url.split('/').pop()) +' .YTtitle'), 
            unescape(mp3url.split('/').pop())
        )
	},
	
	
    // TODO: working towards nuking this...
	getMP3url: function(mp3object) {
		var mp3url,
		    urlCleaner = function(u) {
                if ( u.indexOf('http://') == -1 ) {
                    return window.location.protocol + '//' + window.location.hostname + u
                } else {
                    return u;
                }
            };	
        
		if ( mp3url = this.mp3regex.exec( unescape(mp3object.value) ) ) return urlCleaner( mp3url[1] );
		if ( mp3url = this.mp3regex.exec( jQuery(mp3object).attr('flashvars') ) ) return urlCleaner( mp3url[1] );   // for UFO inserted bare embeds
		return false;
	},
	
		
	getDMid: function(DMobject) {
	    
	    
        // THIS IS BEING CALLED TWICE, SECOND CALL THROWS AN ERROR BECUASE THE FIRST CALL REMOVED THE OBJECT
	    
	   var DMid = this.DMregex.exec( DMobject.src );
           
	   if ( DMid[1].length < 17 ){
	       return DMid[1]
       } else {
           var DMidTranslatorUrl = 'http://joemaller.com/services/dailymotion_id_translator.php?DMid=' + DMid[1] + '&_callback=?';
    	   
           jQuery.getJSON( DMidTranslatorUrl + '', function( json ){
                DMid = json.DMid; 
                // console.log('got ID ' + json.DMid);
                // console.log(DMobject);

              parentObject.replaceLinks( {
                  type: "dailymotion",
                  jq: jQuery(DMobject).parent(),
                  DMid: json.DMid
              } );
              parentObject.getDMtitles(json.DMid);

          } );
              // console.log('fetching id from remote service for ' + DMid[1]);
       }
	},
	

	getQTtags: function(iT){
        // checks for existance of the QT library first, then inserts the tags once loaded
        // TODO: build in a check for MP3 data, some way of recognizing that and inserting an audio-flavor tag
        // TODO: build list of arguments as array, call then QT_GenerateOBJECTText_XHTML.apply('', [arguments])

        // TODO: need to set a global variable so we only push one item onto from of the array


        var QTtag, 
            QTargs = [  iT.img.w, iT.img.h, '', 
                        'autoplay', 'false', 
                        'target', 'myself', 
                        'scale', 'aspect', 
                        'controller', 'false'], 
                        
            addSrc = function(item) {
                // this just adds the first item to the array, if there's an image, it adds that, otherwise
                var firstItem = ( item.constructor == Array ) ? item.shift() : item;
                
                
            };
            
            if ( iT._mp4 ) {
                if ( !iT._img )
                    QTargs.unshift( iT._mp4 )
                    
                QTargs.push( 'qtsrc', iT._mp4 );
                
                
                // what about ordering?
                // if there's 
                    
            }
            
            if ( iT._mp4 ) {
                if ( !iT.img) {
                    // do something
                }
                
                    
            }
            
            
            if ( iT._img ) {
                QTargs.unshift(iT._img);    // send it
            } else {
                switch ('string') {
                    case ( typeof( iT._mp3 ) ):
                    QTargs.unshift(iT._mp3)
                    QTargs.push('qtsrc', iT._mp3)
                        break;
            
                    case ( typeof( iT._mp4 ) ):
                        break;
            
                    default:
                        break;
                }
            }
            
            
            if ( iT._img ) { 
                QTargs.unshift( iT._img) } else {QTargs.unshift( iT._mp3)}
            
        QTtag = function() {
                var QT = '<div style="cursor:pointer;">\n'
                    + QT_GenerateOBJECTText_XHTML( iT._img, iT._w, iT._h - iT.bar.h , "",
                                                  "href", iT._mp4,
                                                  "autoplay", "false",
                                                  "controller", "true",
                                                  "target", "myself",
                                                  "scale", "aspect",
                                                  "type", "audio/x-mpeg" )
                    + '</div>';

           jQuery( '#' + parentObject.nameCleaner(iT._id) + ' a.YTlink:first ').replaceWith(QT)
        };


	    if ( typeof(QT_WriteOBJECT_XHTML) != "function" ) { 
	        jQuery.getScript( this.appleQuickTimeLib, QTtag );
        } else {
	        QTtag()
	    }
        return "getQTtags finished";
	},
	
	formatSeconds: function(seconds) { if (seconds <= 0) return ''; return parseInt(seconds / 60) + ':' + ( ( seconds % 60 < 10 ) ? '0' + seconds % 60 : seconds % 60 ) },
	
	getDimensions: function(iT) {
    	// adds _w and _h to the iT passed in based on iT._obj. Uses several methods to determine the size.
    
        // if ( iT._w && iT._h )
        //     return true;
            
        var j,    
            w = (!iT._w) ? Math.max(iT._obj.width(), iT._obj.attr('width')) : iT._w,
            h = (!iT._h) ? Math.max(iT._obj.height(), iT._obj.attr('height')) : iT._h;

        // console.log('START getDimensions:  w: ' + w + ',  h: ' + h);
    
        // no dimensions determined, start climbing the dom tree to get dimensions of parents
        if ( !w || !h ) {
            iT._obj.parents().each( function() {
                // console.log('IN UR LOOP getDimensions:  w: ' + w + ',  h: ' + h);
                
                j = jQuery(this);
                // console.log(this.tagName)
                if ( w > 0 && h > 0 )
                    return false;    // ends the jQuery each loop
                if ( !w )
                // console.log(j.width())
                // console.log(j.attr('width'))
                    w = (j.attr('width')) ? Math.max( j.width(), j.attr('width') ) : j.width();
                if ( !h )
                    h = ( j.attr('height') ) ? Math.max( j.height(), j.attr('height') ) : j.height();
            })
        }
        // console.log('END getDimensions:  w: ' + w + ',  h: ' + h);
    	
        iT._w =  w ;
        iT._h =  h ;
	},
	
	getBoxDimensions: function(iT) {
	    // assign sizing values for YouTube rectangles
	    // sets the values into known properties of the passed YT object
	    
	    this.getDimensions( iT )

		iT.img.w = iT._w;
		iT.img.h = iT._h;

        if ( typeof(iT._img) != "undefined" ) {
        // if (iT._type == "youtube" || iT._type == "dailymotion" || iT._type == "ted") {
		    iT.img.h -= iT.bar.h;
		    
    		// 0.84 is the default proportion of the YouTube player when the width is <= 400 (400x300 + 36px for the controller)
    		if (iT._w < 400 || iT._h < 336) {
    			// controller will be less than 36px tall
    			if (iT._h/iT._w < 0.84) { 
    				iT.img.w = Math.round(iT._h/0.84);
    				iT.img.h = Math.round(iT.img.w * 0.75);
    			} else {
    				iT.img.h = Math.round(iT._w * 0.75);
    			}
    			
                iT.bar.h = Math.round(iT.img.w * 0.84 - iT.img.w * 0.75);
			
    		} else { 
    			// width greater than 400, controller will be 36px tall
    			if (iT._h/iT._w < (iT._w * 0.75 + 36)/iT._w) { 
    				iT.img.w = Math.round(iT.img.h/0.75);
    			} else {
                    iT.img.h = Math.round(iT.img.w * 0.75);
    			}	
    		}
    		
    		// these variables simplify output positioning
    		iT.img.left = ((iT._w - iT.img.w)/2); 
            iT.img.top = Math.ceil((iT._h - iT.img.h - iT.bar.h)/2);
            iT.bar.top = iT.img.top + iT.img.h;
            
        } else {
            if (iT._h < 36) iT._h = iT.img.h = 36;
            if (iT._w < iT._h * 3) iT._w = iT.img.w = iT._h * 3;
            
            iT.img.left = 0;
            iT.img.top = 0;
            iT.bar.top = 0;
        }
	},
	
	doStats: function() {

        var gaID = "UA-2501271-3";

	    if (typeof(_gat) == 'object') {  // new-style Google Analytics
	        var iTransTracker = _gat._getTracker(gaID); 
	        iTransTracker._initData(); 
            iTransTracker._setDomainName("none");
	        iTransTracker._trackPageview(document.location.toString());
            // console.log('new-style Google Analytics reset ');
            //             console.log(iTransTracker);
        } else if  (typeof(urchinTracker) == 'function') { // old-style Google Analytics
            _uff = 0;   // urchinTracker reset
            _uacct = gaID;
            urchinTracker(document.location.toString());
            // console.log('old-style Google Analytics reset ');
        } else {
            jQuery.getScript((("https:" == document.location.protocol) ? "https://ssl." : "http://www.") + "google-analytics.com/ga.js", function() {
                var iTransTracker = _gat._getTracker(gaID);
                iTransTracker._initData();
                iTransTracker._setDomainName("none");
                iTransTracker._trackPageview(document.location.toString());
                // var iTrans = iTransTracker._createEventTracker('iTransmogrify'); 
                // iTrans._trackEvent('converted', 'this is a test value, will be location?');
                // console.log('New google Analytics loaded ' + typeof(_gat));
                // console.log(iTransTracker);
            })
        }
	},
	
	
	replaceLinks: function(YT) {			
        if (!YT._type)
            return false

		YT.img = {};
		YT.bar = {};

		YT.bar.h = 36; // default size for YouTube, scales down if height is less than 36 (YT.img.w * 0.75 + 36)
		
        if (! YT._bg ) YT._bg = '#000';
        
	    if (YT._type == "dailymotion") {
	        if (typeof(YT.DMid) == 'undefined') return false;
	        YT._id = YT.DMid;
    		YT._page = 'http://iphone.dailymotion.com/video/' + YT._id;
    		YT._img = 'http://www.dailymotion.com/thumbnail/320x240/video/' + YT._id ;

    		YT._w = YT._obj.attr('width');
		    YT._h = YT._w * 0.75 + 36;
	    }
		if (YT._type == "mp3") {
		    YT._id = YT._mp3.split('/').pop();	
		    YT._page = YT._mp3;	    
		    YT._title = this.getMP3titles(YT._mp3);
            
		}


        if ( YT._duration ) {
            if ( YT._duration.toString().indexOf(':') == -1 ) YT._duration = parentObject.formatSeconds( YT._duration );
            YT._title = YT._title += ' &nbsp; <span style="color:#888; font-family:Helvetica;">' + YT._duration + '</span>';
        }
        
        this.getBoxDimensions(YT);

		YT.div = '<div class="YTblock" id="' + this.nameCleaner(YT._id) + '" style="\
    									 	    width: ' + YT._w +'px; \
    										    height: ' + YT._h + 'px; \
    										    display: inline-block;	\
    										    position: relative; \
    										    margin: 0;	\
                                                background: ' + YT._bg + '; \
    										    padding: 0 0 0 0; \
    										    text-align: center; \
    										    line-height: 0;">';
								
		YT.link = '<a class="YTlink" href="' + YT._page + '" target="_new" style="\
                                                background: green; \
                                                text-decoration: none;">';
		
		YT.button = '<div class="YTbutton" style="\
												position: absolute; \
												width: ' + YT._w + 'px; \
												height: ' + YT.img.h + 'px; \
												left: 0; \
												top: 0; \
												margin: 0; \
												padding: 0; \
												background: transparent url(' + this.imageBaseURL + 'play.png) no-repeat center center; " />';
												
		YT.img.tag = '<img src="' + YT._img + '" style="\
												position: absolute; \
												top: ' + YT.img.top + 'px; \
												left: ' + YT.img.left + 'px; \
												width: ' + YT.img.w + 'px; \
												height: ' + YT.img.h + 'px; \
												border:none; \
												margin: 0; \
												padding: 0;" />';
																					
		YT.bottom = '<img class="YT.bottom" src="' + this.imageBaseURL + 'bar.png" style="\
												position: absolute; \
												top: ' + YT.bar.top + 'px; \
												left: 0; \
												height: ' + YT.bar.h + 'px; \
												width:' + YT._w + 'px; \
												border: none; \
												padding: 0; \
												margin: 0; \
												background: transparent;"/>';
												
		YT.titlediv = '<div class="YTtitle" style="\
												position: absolute; \
												left: 0; \
												top: ' + YT.bar.top + 'px; \
												width: ' + (YT._w - YT.bar.h/2) + 'px; \
												padding: ' + Math.floor(YT.bar.h/4) + 'px; \
												margin: 0; \
												font: ' + (YT.bar.h * 0.5) + 'px helvetica; \
                                                -webkit-text-size-adjust: none; \
												text-align: left;  \
												line-height: ' + (YT.bar.h * 0.5) + 'px; \
												color: #ddd; \
												white-space: nowrap; \
												overflow: hidden;';
												
		if (YT._type == 'mp3') YT.titlediv += 'background: transparent url(' + this.imageBaseURL + 'music.png) no-repeat left center;\
		                                        width: ' + (YT.img.w - YT.bar.h/2 - 32) + 'px; \
		                                        padding-left: 32px;'									
		YT.titlediv += '">';

        if (YT._title) { 
            YT.titlediv += YT._title; 
        } else {
            if ( YT._type == 'youtube' )       YT.titlediv += 'Open in YouTube Viewer';
            if ( YT._type == 'dailymotion' )   YT.titlediv += 'View on DailyMotion';
            if ( YT._type == 'mp3' )           YT.titlediv += 'Listen to MP3';
        }
        
        YT.titlediv += '</div>';
												
		YT.infoLink = '<img src="' + this.imageBaseURL + 'fade.png" style="\
				                                position: absolute; \
												top: ' + YT.bar.top + 'px; \
												left: ' + (YT._w - YT.bar.h * 2) + 'px; \
												height: ' + YT.bar.h + 'px; \
												width: ' + (YT.bar.h * 2) + 'px; \
												border: none; \
												padding: 0; \
												margin: 0; \
												-webkit-border-radius: 7px; \
												-moz-border-radius: 7px; \
												background: transparent;" />\
		              <a class="YT.infoLink" href="' + this.joesInfoURL + '" target="_blank" style="\
												position: absolute; \
												top: ' + YT.bar.top + 'px; \
												text-decoration: none; \
												left: ' + (YT._w - YT.bar.h) + 'px; \
												background: transparent; \
												border: none; \
    											padding: 0; \
												margin: 0; \
	                                            text-decoration: none;"> \
				      <img src="' + this.imageBaseURL + 'info.png" style="\
												width:' + YT.bar.h + 'px; \
												border: none; \
												background: transparent; \
												max-width: none; \
												margin:0; \
												padding:0;" /></a>';


        YT.sponsor = '<div style="width: ' + (YT._w) + 'px; background:pink;"><div style="\
                                                background: #888; \
                                                color: #bbb; \
                                                -moz-border-radius: ' + (YT._w * 0.92 / 32) + 'px; \
                                                -webkit-border-radius: ' + (YT._w * 0.92 / 32 ) + 'px; \
                                                -webkit-text-size-adjust: none; \
                                                -webkit-border-image: url(' + this.imageBaseURL + 'sponsor.png)  17 / 10px stretch stretch; \
												font: ' + (YT.bar.h * 0.33) + 'px helvetica; \
                                                line-height: ' + (YT.bar.h * 0.1) + 'px; \
                                                width: 90%; \
												white-space: nowrap; \
                                                overflow: show; \
                                                text-align: center; \
                                                margin: 2px 4%; \
                     ">I AM TOO LONG TO FIT, YOU CAN DELETE ME iTransmogrify sponsorship opportunities available <a style="color:white;" href="mailto:joe@joemaller.com?subject=iTransmogrify+sponsorship">email me</a></div>'; // this obviously needs to pull in from somethign remote, also fix unsupported and Flickr badges
                                                
        if ( typeof(YT._mp4) != "undefined" )
            YT.button = YT.img.tag = ''; // clear playbutton and base image (flashes) under MP4s

        if ( YT._type == 'youtube' ) 
            YT.newHTML = (YT.div + YT.link + YT.img.tag + YT.button + YT.bottom + YT.titlediv + "</a>" + YT.infoLink + "</div>");
        if ( YT._type == 'dailymotion' ) 
            YT.newHTML = (YT.div + YT.link + YT.img.tag + YT.button + YT.bottom + YT.titlediv + "</a>" + YT.infoLink + "</div>");
        if ( YT._type == 'mp3' )    		
            YT.newHTML = (YT.div + YT.link + YT.bottom + YT.titlediv + "</a>" + YT.infoLink + "</div>");
        if ( YT._type == 'ted' || YT._type == 'revver' || YT._type == 'blip.tv' || YT._type == 'mp4')
            YT.newHTML = (YT.div + YT.link + YT.img.tag + YT.button + "</a>" + YT.link + YT.bottom + YT.titlediv + "</a>" + YT.infoLink + "</div>");
        
        // YT.newHTML += YT.sponsor;
        
        YT._obj.replaceWith(YT.newHTML);
        
        if ( typeof(YT._mp4) != "undefined" && YT._mp4 != '' )
          this.getQTtags(YT);
          
		if ( YT._type == 'youtube' && !YT._title )
		    this.getYTTitles(YT._id); // replace YouTube titles
	},

    unsupported: {
        doesNotYet: " does not yet offer iPod/iPhone compatible videos",
        
        get: function(context) {
            // MotionBox
            jQuery('embed[src*=motionbox.com]').each(function(){
                var knownText, obj,
                    regex = /motionbox.com.*id%3D([^%]+)%?/;
                if ( knownText = regex.exec( jQuery(this).attr('src') ) ) {
                    obj = jQuery(this);
                    obj = ( obj.parent().is('object') ) ? obj.parent() : obj;
                   try {                         
                        parentObject.unsupported.replace( {_obj: obj, _page: 'http://www.motionbox.com/video/player/' + knownText[1], _title: 'MotionBox video page', _typeLabel:'Motion Box'} );
                      } catch (err) {}
                } 
            })
 
            // RedLasso
            jQuery('param[value*=redlasso.com]').each(function(){
                var knownText, obj,
                    regex = /redlasso.com/;
                if ( knownText = regex.exec( jQuery(this).attr('value') ) ) {
                    obj = jQuery(this);
                    obj = ( obj.parent().is('object') ) ? obj.parent() : obj;
                   try {                         
                        parentObject.unsupported.replace( {_obj: obj, _page: 'mailto:joe@joemaller.com?subject=RedLasso%20invite%20for%20iTransmogrify%21', _title: 'iTransmogrify! needs a RedLasso invite, spare one?', _typeLabel:'RedLasso' } );
                      } catch (err) {}
                } 
            })

            // Viddler
            // TODO: what is the Viddler API capable of?
            jQuery('embed[src*=viddler.com]').each(function(){
                var knownText, obj,
                    regex = /viddler.com\/(?:player|simple)\/([a-zA-Z0-9]+)/;
                if ( knownText = regex.exec( jQuery(this).attr('src') ) ) {
                    obj = jQuery(this);
                    obj = ( obj.parent().is('object') ) ? obj.parent() : obj;
                    try {                         
                        parentObject.unsupported.replace( {_obj: obj, _typeLabel:'Viddler'} );
                       } catch (err) {}
                } 
            })

            // Vimeo
            // TODO: integrate the Vimeo API
            jQuery('object[data*=vimeo.com]').each(function(){
                var knownText, obj,
                    regex = /vimeo.com\/.*clip_id=([0-9]+)&/;
                if ( knownText = regex.exec( jQuery(this).attr('data') ) ) {
                    obj = jQuery(this);
                    obj = ( obj.parent().is('object') ) ? obj.parent() : obj;
                    try {                         
                        parentObject.unsupported.replace( { _obj: obj, _page: 'http://www.vimeo.com/' + knownText[1], _typeLabel:'Vimeo', _title: 'Vimeo video page' } );
                       } catch (err) {}
                } 
            })
            
            // LiveLeak
            // liveleak thumbnail location can be retrieved via page headers, looks like this:  http://cdn-##.liveleak.com/liveleak/thumbs/####/Month/#/444b68e2178658_1_thumb-big.jpg
            jQuery('object[data*=liveleak.com], embed[flashvars*=liveleak.com], embed[src*=liveleak.com]').each(function(){
                var knownText, obj,
                    regex = /token(?:=|%3D)([0-9a-z]{3}_[0-9]+)/;
                if ( ( knownText = regex.exec( jQuery(this).attr('data') ) ) ||
                     ( knownText = regex.exec( jQuery(this).attr('flashvars') ) ) ||
                     ( knownText = ( /liveleak.com\/e\/([0-9a-z]{3}_[0-9]+)/).exec( jQuery(this).attr('src') ) ) ) {
                        obj = jQuery(this);
                        obj = ( obj.parent().is('object') ) ? obj.parent() : obj;
                        try {                            // try prevents errors where a match might include a nested embed
                            parentObject.unsupported.replace({ _obj: obj, 
                                                               _typeLabel:'LiveLeak', 
                                                               _title:'LiveLeak Video Page', 
                                                               _page:'http://www.liveleak.com/view?i=' + knownText[1] 
                            } );
                        } catch (err) {}
                   }
            })

            // NBC
            jQuery('embed[src*=widgets.nbc.com]').each(function(){
                var knownText, obj,
                    regex = /widgets.nbc.com/;
                if ( knownText = regex.exec( jQuery(this).attr('src') ) ) {
                    obj = jQuery(this);
                    obj = ( obj.parent().is('object') ) ? obj.parent() : obj;
                    try {                         
                        parentObject.unsupported.replace( { _obj: obj,
                                                            _typeLabel:'NBC.com', 
                                                        } );
                       } catch (err) {}
                } 
            })
        
            // MegaVideo
            jQuery('param[value*=megavideo.com], embed[src*=megavideo.com]').each(function(){
                var knownText, obj,
                    regex = /megavideo.com\/v\/([A-Z0-9]+)[a-z0-9]{32}\.[0-9]{10}\.[0-9]$/;
                if ( ( knownText = regex.exec( jQuery(this).attr('src') ) ) ||
                     ( knownText = regex.exec( jQuery(this).attr('value') ) )
                   ) {
                        // TODO: move this repeated obj determining stuff into a function, 
                        obj = jQuery(this);
                        obj = ( obj.parent().is('object') ) ? obj.parent() : obj;
                        try {                            // try prevents errors where a match might include a nested embed
                            parentObject.unsupported.replace( { _obj: obj,
                                                                _page:'http://www.megavideo.com/?v=' + knownText[1], 
                                                                _typeLabel:'MegaVideo', 
                                                                _title:"MegaVideo Video Page" 
                                                            } );
                           } catch (err) {}
                   }
            })
        },
        
        
        replace: function(iT) {
            parentObject.getDimensions(iT);

            var output, img, imgDiv, textDiv, outerDiv, tablediv, message;
                                 
            if (!iT._typeLabel) iT._typeLabel = '';

            // outerdiv                      
            outerDiv = jQuery( document.createElement('div') )
                        .css({ width: iT._w + 'px', 
                               height: iT._h + 'px', 
                               position: 'relative', 
                               fontFamily: 'helvetica', 
                               color: '#aaa',
                               background: '#555',
                               margin: 0,
                               padding: 0,
                               fontSize: iT._h/14 + "px", // base line-height on 14 theoretical lines in the box. Seems ok
                               display: 'block'
                              })
                                          
          textDiv = jQuery( document.createElement('div') )
                        .css({ display: 'table-cell', 
                               position: 'relative',
                               width: '100%', 
                               height: '100%', 
                               padding: '0 10%', 
                               verticalAlign: 'middle', 
                               textAlign: 'center', 
                               fontSize: '0.8em', 
                               lineHeight: '1.6em'}
                              ) 

          if ( iT._title ) {
              if ( iT._page && iT._page != document.location.href ) {        // don't add links to the page we're on      
                  textDiv.append(
                      jQuery( document.createElement('a') )
                        .attr({'href': iT._page, 'target': '_new'})
                        .text(iT._title)
                        .css( { color: '#fff', 
                                textDecoration: 'none', 
                                fontWeight: 'bold', 
                                fontSize: '1.25em', 
                                opacity: 0.75 
                            } ) )
              } else {
                  textDiv.append(
                      jQuery( document.createElement('span') )
                        .text(iT._title)
                        .css( { fontWeight: 'bold', 
                                fontSize: '1.25em' 
                            } ) )
              }
              textDiv.append( document.createElement('br') );
          }

          textDiv.append('This ' + iT._typeLabel  + ' video is not yet available in a MobileSafari compatible format.'); // TODO sniff whether or not this is an iPhone or iPod Touch, use that instead of 'MobileSafari'        
          
          textDiv = jQuery(document.createElement('div'))
                        .css({ position: 'absolute', 
                               display: 'table', 
                               height: '100%', 
                               width: '100%', 
                               textShadow: '#000 0 0.2em 0.25em'
                            }).append(textDiv)
          
          // background image overlay:
          imgDiv = jQuery(document.createElement('div')).append( 
                      jQuery(document.createElement('img'))
                        .attr('src', parentObject.imageBaseURL + 'unsupported.png')
                        .css({ width: '100%', 
                               height: '100%', 
                               padding: 0, 
                               margin: 0, 
                               background: 'transparent'
                             } ) )
                   .css({ position: 'absolute', 
                          top: 0, 
                          left: 0, 
                          margin: 0, 
                          padding: 0, 
                          width: '100%', 
                          height: '100%'
                      });

            if (iT._img) {    
                var bgImgDiv = imgDiv.clone();
                bgImgDiv.children('img').attr('src', iT._img);
                bgImgDiv.css('opacity', '0.6')
                outerDiv.prepend(bgImgDiv);
            }

            outerDiv.append(imgDiv).append(textDiv)
            outerDiv.append(
                jQuery(document.createElement('a')).attr({'href':'http://itransmogrify.googlecode.com', 'target':'_new'})
                    .css({
                        position: 'absolute',
                        margin: 0, 
                        padding: 0, 
                        bottom: '0.5em', 
                        right: '10px', 
                        fontSize: '0.7em', 
                        fontWeight: 'bold', 
                        color: '#888', 
                        opacity: 0.75,
                        textDecoration: 'none'
                        })
                    .text('iTransmogrify!')
                )

                if (iT._obj.parent().is('object')) {
                    iT._obj.parent().replaceWith(outerDiv)
                } else {
                    iT._obj.replaceWith(outerDiv)
                }       
            }  
    }
}.init()


// Known issues
// TODO: Fix MP3 sizing
// TODO: DailyMotion is broken
// TODO: Go to the apple store and test this on an iPod Touch